"""
用户API模块

提供用户管理相关的所有API接口，包括：
- 用户注册、登录、认证
- 用户信息的增删改查
- 用户角色管理
- 权限验证
"""

from fastapi import APIRouter, Depends, HTTPException, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from pydantic import BaseModel, EmailStr
from passlib.context import CryptContext
from datetime import datetime, timezone, timedelta
from typing import Optional, List
import jwt
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func
from db.models import User, Role, UserRole
from db.session import get_db
from services.permission import require_permission, get_permission_service, PermissionCodes

router = APIRouter(prefix="/users", tags=["用户"])

# JWT配置
SECRET_KEY = "your-secret-key-here-change-in-production"  # 生产环境需要更改
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30

# 密码加密上下文
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
security = HTTPBearer()

class UserCreate(BaseModel):
    """用户创建请求模型"""
    username: str
    email: EmailStr
    password: str

class UserLogin(BaseModel):
    """用户登录请求模型"""
    username: str
    password: str
    captcha_id: str
    captcha_text: str

class UserUpdate(BaseModel):
    """用户更新请求模型"""
    username: Optional[str] = None
    email: Optional[EmailStr] = None
    role: Optional[str] = None
    status: Optional[str] = None
    role_ids: Optional[List[int]] = None
    password: Optional[str] = None
    full_name: Optional[str] = None
    bio: Optional[str] = None

class UserResponse(BaseModel):
    """用户响应模型"""
    id: int
    username: str
    email: str
    role: str = "user"
    status: str = "active"
    created_at: datetime
    updated_at: datetime
    roles: List[dict] = []

    class Config:
        from_attributes = True

class UserListResponse(BaseModel):
    """用户列表响应模型"""
    users: List[UserResponse]
    total: int
    page: int
    pageSize: int

class Token(BaseModel):
    """JWT令牌响应模型"""
    access_token: str
    token_type: str

def verify_password(plain_password, hashed_password):
    """
    验证密码
    
    Args:
        plain_password: 明文密码
        hashed_password: 哈希密码
        
    Returns:
        bool: 密码是否匹配
    """
    return pwd_context.verify(plain_password, hashed_password)

def get_password_hash(password):
    """
    生成密码哈希
    
    Args:
        password: 明文密码
        
    Returns:
        str: 哈希后的密码
    """
    return pwd_context.hash(password)

def create_access_token(data: dict, expires_delta: Optional[timedelta] = None):
    """
    创建JWT访问令牌
    
    Args:
        data: 要编码的数据
        expires_delta: 过期时间增量
        
    Returns:
        str: JWT令牌
    """
    to_encode = data.copy()
    if expires_delta:
        expire = datetime.now(timezone.utc) + expires_delta
    else:
        expire = datetime.now(timezone.utc) + timedelta(minutes=15)
    to_encode.update({"exp": expire})
    encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
    return encoded_jwt

async def get_current_user(credentials: HTTPAuthorizationCredentials = Depends(security), db: AsyncSession = Depends(get_db)):
    """
    获取当前登录用户
    
    Args:
        credentials: JWT凭据
        db: 数据库会话
        
    Returns:
        User: 当前用户对象
        
    Raises:
        HTTPException: 认证失败时抛出异常
    """
    try:
        payload = jwt.decode(credentials.credentials, SECRET_KEY, algorithms=[ALGORITHM])
        username: str = payload.get("sub")
        if username is None:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="Invalid authentication credentials",
                headers={"WWW-Authenticate": "Bearer"},
            )
        result = await db.execute(select(User).where(User.username == username))
        user = result.scalar_one_or_none()
        if user is None:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="User not found",
                headers={"WWW-Authenticate": "Bearer"},
            )
        return user
    except jwt.PyJWTError:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid authentication credentials",
            headers={"WWW-Authenticate": "Bearer"},
        )

@router.post("/", response_model=UserResponse, summary="创建用户")
async def create_user(user: UserCreate, db: AsyncSession = Depends(get_db)):
    """
    创建新用户
    
    Args:
        user: 用户创建数据
        db: 数据库会话
        
    Returns:
        UserResponse: 创建的用户信息
        
    Raises:
        HTTPException: 用户名或邮箱已存在时抛出异常
    """
    result = await db.execute(select(User).where(User.username == user.username))
    if result.scalar_one_or_none():
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Username already registered"
        )
    
    result = await db.execute(select(User).where(User.email == user.email))
    if result.scalar_one_or_none():
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Email already registered"
        )
    
    hashed_password = get_password_hash(user.password)
    db_user = User(
        username=user.username,
        email=user.email,
        hashed_password=hashed_password,
        is_active=True,
        is_admin=False
    )
    
    db.add(db_user)
    await db.commit()
    await db.refresh(db_user)
    
    return UserResponse(
        id=int(db_user.id),
        username=str(db_user.username),
        email=str(db_user.email),
        role="user",
        status="active",
        created_at=db_user.create_time,
        updated_at=db_user.update_time,
        roles=[]
    )

@router.post("/register", response_model=UserResponse, summary="用户注册")
async def register(user: UserCreate, db: AsyncSession = Depends(get_db)):
    """
    用户注册
    
    Args:
        user: 用户注册数据
        db: 数据库会话
        
    Returns:
        UserResponse: 注册成功的用户信息
        
    Raises:
        HTTPException: 用户名或邮箱已存在时抛出异常
    """
    result = await db.execute(select(User).where(User.username == user.username))
    if result.scalar_one_or_none():
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Username already registered"
        )
    
    result = await db.execute(select(User).where(User.email == user.email))
    if result.scalar_one_or_none():
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Email already registered"
        )
    
    hashed_password = get_password_hash(user.password)
    db_user = User(
        username=user.username,
        email=user.email,
        hashed_password=hashed_password,
        is_active=True,
        is_admin=False
    )
    
    db.add(db_user)
    await db.commit()
    await db.refresh(db_user)
    
    return UserResponse(
        id=int(db_user.id),
        username=str(db_user.username),
        email=str(db_user.email),
        role="user",
        status="active",
        created_at=db_user.create_time,
        updated_at=db_user.update_time,
        roles=[]
    )

@router.post("/login", response_model=Token, summary="用户登录")
async def login(user: UserLogin, db: AsyncSession = Depends(get_db)):
    """
    用户登录
    
    Args:
        user: 用户登录数据
        db: 数据库会话
        
    Returns:
        Token: JWT访问令牌
        
    Raises:
        HTTPException: 验证码错误或用户名密码错误时抛出异常
    """
    # 验证验证码
    from .captcha_api import CaptchaVerifyRequest, verify_captcha
    try:
        captcha_request = CaptchaVerifyRequest(captcha_id=user.captcha_id, captcha_text=user.captcha_text)
        await verify_captcha(captcha_request)
    except HTTPException as e:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="验证码错误"
        )
    
    result = await db.execute(select(User).where(User.username == user.username))
    db_user = result.scalar_one_or_none()
    
    if not db_user or not verify_password(user.password, db_user.hashed_password):
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Incorrect username or password",
            headers={"WWW-Authenticate": "Bearer"},
        )
    
    access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
    access_token = create_access_token(
        data={"sub": db_user.username}, expires_delta=access_token_expires
    )
    return {"access_token": access_token, "token_type": "bearer"}

@router.get("/me", response_model=UserResponse, summary="获取当前用户信息")
async def get_current_user_profile(current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db)):
    """
    获取当前登录用户信息
    
    Args:
        current_user: 当前用户对象
        db: 数据库会话
        
    Returns:
        UserResponse: 当前用户详细信息
    """
    # 获取用户角色
    user_roles_result = await db.execute(
        select(UserRole, Role)
        .join(Role, UserRole.role_id == Role.id)
        .where(UserRole.user_id == current_user.id)
    )
    user_roles = []
    for ur, role in user_roles_result:
        user_roles.append({
            "id": int(role.id),
            "name": str(role.name),
            "code": str(role.code),
            "description": str(role.description) if role.description else None
        })
    
    return UserResponse(
        id=int(current_user.id),
        username=str(current_user.username),
        email=str(current_user.email),
        role="admin" if bool(current_user.is_admin) else "user",
        status="active" if bool(current_user.is_active) else "inactive",
        created_at=current_user.create_time,
        updated_at=current_user.update_time,
        roles=user_roles
    )

@router.put("/{user_id}", response_model=UserResponse, summary="更新用户信息")
@require_permission(PermissionCodes.USER_UPDATE)
async def update_user(
    user_id: int,
    user_update: UserUpdate,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
):
    """
    更新用户信息
    
    Args:
        user_id: 用户ID
        user_update: 用户更新数据
        current_user: 当前用户对象
        db: 数据库会话
        
    Returns:
        UserResponse: 更新后的用户信息
        
    Raises:
        HTTPException: 用户不存在或权限不足时抛出异常
    """
    # 查找用户
    result = await db.execute(select(User).where(User.id == user_id))
    user = result.scalar_one_or_none()
    
    if not user:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="User not found"
        )
    
    # 更新用户信息
    if user_update.username is not None:
        # 检查用户名是否已被使用
        existing_user = await db.execute(select(User).where(
            User.username == user_update.username,
            User.id != user_id
        ))
        if existing_user.scalar_one_or_none():
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Username already registered"
            )
        user.username = user_update.username
    
    if user_update.email is not None:
        # 检查邮箱是否已被使用
        existing_user = await db.execute(select(User).where(
            User.email == user_update.email,
            User.id != user_id
        ))
        if existing_user.scalar_one_or_none():
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Email already registered"
            )
        user.email = user_update.email
    
    # 更新角色关联
    if user_update.role_ids is not None:
        # 删除现有角色关联
        await db.execute(select(UserRole).where(UserRole.user_id == user_id))
        await db.commit()
        
        # 添加新的角色关联
        for role_id in user_update.role_ids:
            # 验证角色是否存在
            role_result = await db.execute(select(Role).where(Role.id == role_id))
            role = role_result.scalar_one_or_none()
            if role:
                user_role = UserRole(user_id=user_id, role_id=role_id)
                db.add(user_role)
        
        # 更新is_admin字段（向后兼容）
        admin_role_result = await db.execute(
            select(Role).where(Role.code == "admin")
        )
        admin_role = admin_role_result.scalar_one_or_none()
        if admin_role and admin_role.id in user_update.role_ids:
            user.is_admin = True
        else:
            user.is_admin = False
    
    # 更新密码
    if user_update.password is not None:
        user.hashed_password = get_password_hash(user_update.password)
    
    # 更新扩展信息
    if user_update.full_name is not None:
        user.full_name = user_update.full_name
    
    if user_update.bio is not None:
        user.bio = user_update.bio
    
    # 更新状态
    if user_update.status is not None:
        user.is_active = (user_update.status == "active")
    
    # 更新时间
    from datetime import datetime
    user.update_time = datetime.now(timezone.utc)
    
    await db.commit()
    await db.refresh(user)
    
    # 获取用户角色
    user_roles_result = await db.execute(
        select(UserRole, Role)
        .join(Role, UserRole.role_id == Role.id)
        .where(UserRole.user_id == user_id)
    )
    user_roles = []
    for ur, role in user_roles_result:
        user_roles.append({
            "id": int(role.id),
            "name": str(role.name),
            "code": str(role.code),
            "description": str(role.description) if role.description else None
        })
    
    return UserResponse(
        id=int(user.id),
        username=str(user.username),
        email=str(user.email),
        role="admin" if bool(user.is_admin) else "user",
        status="active" if bool(user.is_active) else "inactive",
        created_at=user.create_time,
        updated_at=user.update_time,
        roles=user_roles
    )

@router.delete("/{user_id}", summary="删除用户")
@require_permission(PermissionCodes.USER_DELETE)
async def delete_user(
    user_id: int,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
):
    """
    删除用户
    
    Args:
        user_id: 用户ID
        current_user: 当前用户对象
        db: 数据库会话
        
    Returns:
        dict: 删除结果
        
    Raises:
        HTTPException: 用户不存在或权限不足时抛出异常
    """
    # 查找用户
    result = await db.execute(select(User).where(User.id == user_id))
    user = result.scalar_one_or_none()
    
    if not user:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="User not found"
        )
    
    # 防止删除自己
    if user.id == current_user.id:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Cannot delete yourself"
        )
    
    await db.delete(user)
    await db.commit()
    
    return {"message": "User deleted successfully"}

@router.get("/", response_model=UserListResponse, summary="获取用户列表")
@require_permission(PermissionCodes.USER_READ)
async def get_all_users(
    page: int = 1,
    pageSize: int = 10,
    search: str = "",
    role: str = "",
    current_user: User = Depends(get_current_user), 
    db: AsyncSession = Depends(get_db)
):
    """
    获取用户列表（分页）
    
    Args:
        page: 页码
        pageSize: 每页数量
        search: 搜索关键词
        role: 角色筛选
        current_user: 当前用户对象
        db: 数据库会话
        
    Returns:
        UserListResponse: 用户列表和分页信息
        
    Raises:
        HTTPException: 权限不足时抛出异常
    """
    # 构建基础查询
    query = select(User).outerjoin(UserRole, User.id == UserRole.user_id).outerjoin(Role, UserRole.role_id == Role.id)
    
    # 添加搜索条件
    if search:
        query = query.where(User.username.contains(search) | User.email.contains(search))
    
    # 添加角色筛选 - 基于角色代码
    if role:
        query = query.where(Role.code == role)
    
    # 获取总数
    count_query = select(func.count(User.id)).outerjoin(UserRole, User.id == UserRole.user_id).outerjoin(Role, UserRole.role_id == Role.id)
    if search:
        count_query = count_query.where(User.username.contains(search) | User.email.contains(search))
    if role:
        count_query = count_query.where(Role.code == role)
    
    total_result = await db.execute(count_query)
    total = total_result.scalar() or 0
    
    # 添加分页
    query = query.offset((page - 1) * pageSize).limit(pageSize)
    
    # 执行查询
    result = await db.execute(query)
    users = result.scalars().all()
    
    # 获取所有用户的角色信息
    user_ids = [user.id for user in users]
    user_roles_result = await db.execute(
        select(UserRole, Role)
        .join(Role, UserRole.role_id == Role.id)
        .where(UserRole.user_id.in_(user_ids))
    )
    
    # 按用户ID分组角色信息
    user_roles_map = {}
    for ur, role in user_roles_result:
        if ur.user_id not in user_roles_map:
            user_roles_map[ur.user_id] = []
        user_roles_map[ur.user_id].append({
            "id": int(role.id),
            "name": str(role.name),
            "code": str(role.code),
            "description": str(role.description) if role.description else None
        })
    
    return UserListResponse(
        users=[
            UserResponse(
                id=int(user.id),
                username=str(user.username),
                email=str(user.email),
                role="admin" if bool(user.is_admin) else "user",
                status="active" if bool(user.is_active) else "inactive",
                created_at=user.create_time,
                updated_at=user.update_time,
                roles=user_roles_map.get(int(user.id), [])
            )
            for user in users
        ],
        total=total,
        page=page,
        pageSize=pageSize
    )
